Loading libraries

library(HDF5Array)
library(ggplot2)
library(Matrix)
library(pheatmap)
library(RColorBrewer)
library(uwot)
library(grid)
library(gridExtra)
library(GEDI)

Directories

dir_data<- "../data_objects/"
dir_data_hdf5<- paste0(dir_data, "COVID19_SCE/")

Functions

#' Plot 2D embedding 
#'
#' Plot a 2D representation (embedding) of cells
#' @param embedding_mat Embedding
#' @param colour vector of variable to plot
#' @param randomize Logical. Whether to randomize data before plotting.
#'
#' @return ggplot2 object
#' @export
#'
plot_embedding <- function(embedding_mat,colour,randomize=T, size_point=0.05) {
  # create a data frame that will have the embedding as well as the colors
  embedding_obj <- data.frame(
    Dim1=embedding_mat[,1],
    Dim2=embedding_mat[,2],
    Var=colour )

  # randomize the order of the objects
  if( randomize ) {
    embedding_obj <- embedding_obj[ sample.int(nrow(embedding_obj)), ]
  }
  # create the plots
  if(is.numeric(colour)) # the color variable is numeric
  {
    #embedding_obj$Var <- embedding_obj$Var - mean(embedding_obj$Var)
    lim <- stats::quantile(abs(embedding_obj$Var),0.99)
    ggplot2::ggplot(
      embedding_obj, ggplot2::aes_string( x="Dim1", y="Dim2", colour="Var"))+
      ggplot2::geom_point(size=size_point)+
      ggplot2::theme_minimal()+
      ggplot2::scale_color_gradientn( limits=c(-lim,lim), colours=c("blue","light grey","red"), oob=scales::squish )
  } else {
    ggplot2::ggplot(
      embedding_obj, ggplot2::aes_string( x="Dim1", y="Dim2", colour="Var"))+
      ggplot2::geom_point(size=size_point)+
      ggplot2::theme_minimal()+
      ggplot2::guides(colour=ggplot2::guide_legend(override.aes=list(size=3)))

  }
}

Loading data

# Reading SCE object
sce<- loadHDF5SummarizedExperiment(dir=dir_data_hdf5)
Loading required package: SingleCellExperiment
Loading required package: SummarizedExperiment
Loading required package: GenomicRanges
Loading required package: GenomeInfoDb
Loading required package: Biobase
Welcome to Bioconductor

    Vignettes contain introductory material; view with
    'browseVignettes()'. To cite Bioconductor, see
    'citation("Biobase")', and for packages 'citation("pkgname")'.

Attaching package: 'Biobase'
The following object is masked from 'package:MatrixGenerics':

    rowMedians
The following objects are masked from 'package:matrixStats':

    anyMissing, rowMedians
meta<- data.frame(colData(sce))

# Reading GEDI model ( cohort1 results)
model<- readRDS(paste0(dir_data, "COVID19_gedi_model_cohort1.rds"))

# reorder meta based on GEDI order
meta<- meta[model$aux$cellIDs,]

Vector fields

Severe vs control

t( model$aux$inputH)
            (Intercept) group_per_samplemild group_per_samplesevere
C19-CB-0001           1                    1                      0
C19-CB-0003           1                    1                      0
C19-CB-0002           1                    1                      0
C19-CB-0005           1                    1                      0
C19-CB-0009           1                    0                      1
C19-CB-0012           1                    0                      1
C19-CB-0013           1                    0                      1
C19-CB-0011           1                    0                      1
C19-CB-0008           1                    0                      1
C19-CB-0020           1                    0                      1
C19-CB-0021           1                    0                      1
C19-CB-0016           1                    0                      1
C19-CB-0198           1                    0                      1
C19-CB-0204           1                    1                      0
C19-CB-0199           1                    0                      1
C19-CB-0214           1                    1                      0
C19-CB-0053           1                    1                      0
C19-CB-0052           1                    1                      0
P18F                  1                    0                      0
P17H                  1                    0                      0
P20H                  1                    0                      0
P15F                  1                    0                      0
P08H                  1                    0                      0
P13H                  1                    0                      0
P07H                  1                    0                      0
P06F                  1                    0                      0
P04H                  1                    0                      0
C2P01H                1                    0                      0
P09H                  1                    0                      0
P02H                  1                    0                      0
C2P05F                1                    0                      0
C2P07H                1                    0                      0
C2P13F                1                    0                      0
C2P16H                1                    0                      0
C2P10H                1                    0                      0
C2P19H                1                    0                      0
C2P15H                1                    0                      0
one_k_v3              1                    0                      0
Five_k_v3             1                    0                      0
Ten_k_v3              1                    0                      0
# Project the vector field on the SVD space
vectorField <- svd.vectorField.gedi(
  model, start.cond = c(1,0,0), end.cond = c(1,0,1), scale_cond_vector=0.3 )
# The vectorField list contains the SVD results:
#  The 'u' object contains the gene loadings (JxK)
#  The 'd' object is the singular values
#  The 'v' object is a 2N x K matrix, with the first N rows containing the
#   start coordinates, and the second N rows containing the end coordinates

# Getting overall velocity
DiffExp <- getDiffExp.gedi( model, c(0,0,1) ) 
velocity<- colSums(DiffExp^2)
# Euclidean distance
set.seed(43)
umap_vectorField <- umap(
  vectorField$v %*% diag(vectorField$d), min_dist=0.5,
  metric="euclidean")

Embedding plots

## Cell type embedding indices
ggp<- plot_embedding( umap_vectorField[vectorField$embedding_indices,], meta$id.celltype) +
    theme_void() +
    theme(legend.position ="none")
Warning: `aes_string()` was deprecated in ggplot2 3.0.0.

Warning: Please use tidy evaluation idioms with `aes()`.

Warning: See also `vignette("ggplot2-in-packages")` for more information.
ggp

## Saving the colors
g <- ggplot_build(ggp)

df<- g$data[[1]]
df<- unique(df[,c("group", "colour")])
df<- df[order(df$group),]
temp_vec<- levels(meta$id.celltype)
temp_vec<- temp_vec[temp_vec %in% unique(meta$id.celltype)]
df$celltype<- temp_vec

vec_colors<- df$colour
names(vec_colors)<- df$celltype


ggp<- plot_embedding( umap_vectorField[vectorField$embedding_indices,], meta$id.celltype) +
    theme_void() +
    theme(legend.position ="right")

legend <- cowplot::get_legend(ggp)

grid.newpage()
grid.draw(legend)

## Donor embedding indices
plot_embedding( umap_vectorField[vectorField$embedding_indices,], meta$donor) +
    theme_void() +
    theme(legend.position ="none")

ggp<- plot_embedding( umap_vectorField[vectorField$embedding_indices,], meta$donor) +
    theme_void() +
    theme(legend.position ="right")

legend <- cowplot::get_legend(ggp)

grid.newpage()
grid.draw(legend)

Vector field plots

## Cell type 
plot_vectorField( umap_vectorField, meta$id.celltype, nbin=50, minNum=30 ) +
    theme_void() +
    theme(legend.position ="none") +
    scale_color_manual(values=vec_colors)

ggp<- plot_vectorField( umap_vectorField, meta$id.celltype, nbin=50, minNum=30 ) +
    theme_void() +
    theme(legend.position ="right") +
    scale_color_manual(values=vec_colors )

legend <- cowplot::get_legend(ggp)

grid.newpage()
grid.draw(legend)

Boxplot of the magnitude of the gene expression changes

meta$velocity_severe<- velocity 

## limit for boxplot
lim <- stats::quantile(abs(meta$velocity_severe),0.999)
meta$id.celltype<- factor(meta$id.celltype, levels=rev(levels(meta$id.celltype) ) )

ggp<- ggplot(meta, aes(velocity_severe,id.celltype, color = id.celltype ) ) +
    geom_boxplot(outlier.shape = NA) +
    xlim(0, lim) +
    scale_color_manual(values=vec_colors) +
    theme_minimal() +
    theme(legend.position ="none")

ggp
Warning: Removed 87 rows containing non-finite values (`stat_boxplot()`).

sessionInfo()
R version 4.0.0 (2020-04-24)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: CentOS Linux 7 (Core)

Matrix products: default
BLAS/LAPACK: /cvmfs/soft.computecanada.ca/easybuild/software/2020/Core/imkl/2020.1.217/compilers_and_libraries_2020.1.217/linux/mkl/lib/intel64_lin/libmkl_gf_lp64.so

locale:
 [1] LC_CTYPE=en_CA.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_CA.UTF-8        LC_COLLATE=en_CA.UTF-8    
 [5] LC_MONETARY=en_CA.UTF-8    LC_MESSAGES=en_CA.UTF-8   
 [7] LC_PAPER=en_CA.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_CA.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
 [1] grid      parallel  stats4    stats     graphics  grDevices utils    
 [8] datasets  methods   base     

other attached packages:
 [1] SingleCellExperiment_1.12.0 SummarizedExperiment_1.20.0
 [3] Biobase_2.50.0              GenomicRanges_1.42.0       
 [5] GenomeInfoDb_1.26.7         GEDI_0.0.0.9000            
 [7] gridExtra_2.3               uwot_0.1.10                
 [9] RColorBrewer_1.1-2          pheatmap_1.0.12            
[11] ggplot2_3.4.2               HDF5Array_1.18.1           
[13] rhdf5_2.34.0                DelayedArray_0.16.3        
[15] IRanges_2.24.1              S4Vectors_0.28.1           
[17] MatrixGenerics_1.2.1        matrixStats_0.58.0         
[19] BiocGenerics_0.36.0         Matrix_1.3-3               

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.8.3           lattice_0.20-41        digest_0.6.27         
 [4] utf8_1.2.1             RSpectra_0.16-0        plyr_1.8.6            
 [7] R6_2.5.0               backports_1.2.1        evaluate_0.14         
[10] highr_0.8              pillar_1.8.1           zlibbioc_1.36.0       
[13] rlang_1.1.0            data.table_1.14.0      jquerylib_0.1.3       
[16] checkmate_2.1.0        rmarkdown_2.7          labeling_0.4.2        
[19] stringr_1.5.0          RcppEigen_0.3.3.9.1    RCurl_1.98-1.3        
[22] munsell_0.5.0          metR_0.13.0            compiler_4.0.0        
[25] xfun_0.22              pkgconfig_2.0.3        htmltools_0.5.1.1     
[28] tidyselect_1.2.0       tibble_3.2.1           GenomeInfoDbData_1.2.4
[31] codetools_0.2-16       fansi_0.4.2            dplyr_1.1.1           
[34] withr_2.5.0            bitops_1.0-6           rhdf5filters_1.2.0    
[37] jsonlite_1.8.4         gtable_0.3.0           lifecycle_1.0.3       
[40] magrittr_2.0.3         scales_1.2.1           cachem_1.0.4          
[43] cli_3.6.1              stringi_1.5.3          farver_2.1.0          
[46] XVector_0.30.0         bslib_0.2.4            generics_0.1.3        
[49] vctrs_0.6.1            cowplot_1.1.1          RcppAnnoy_0.0.18      
[52] Rhdf5lib_1.12.1        tools_4.0.0            glue_1.6.2            
[55] fastmap_1.1.0          yaml_2.2.1             colorspace_2.0-0      
[58] memoise_2.0.0          knitr_1.31             sass_0.3.1            
LS0tCnRpdGxlOiAiQ09WSUQtMTkgQ29ob3J0MSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKLS0tCgojIExvYWRpbmcgbGlicmFyaWVzCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KCmxpYnJhcnkoSERGNUFycmF5KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeSh1d290KQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KEdFREkpCgpgYGAKCiMgRGlyZWN0b3JpZXMKCmBgYHtyfQoKZGlyX2RhdGE8LSAiLi4vZGF0YV9vYmplY3RzLyIKZGlyX2RhdGFfaGRmNTwtIHBhc3RlMChkaXJfZGF0YSwgIkNPVklEMTlfU0NFLyIpCgpgYGAKCiMgRnVuY3Rpb25zCgpgYGB7cn0KCiMnIFBsb3QgMkQgZW1iZWRkaW5nIAojJwojJyBQbG90IGEgMkQgcmVwcmVzZW50YXRpb24gKGVtYmVkZGluZykgb2YgY2VsbHMKIycgQHBhcmFtIGVtYmVkZGluZ19tYXQgRW1iZWRkaW5nCiMnIEBwYXJhbSBjb2xvdXIgdmVjdG9yIG9mIHZhcmlhYmxlIHRvIHBsb3QKIycgQHBhcmFtIHJhbmRvbWl6ZSBMb2dpY2FsLiBXaGV0aGVyIHRvIHJhbmRvbWl6ZSBkYXRhIGJlZm9yZSBwbG90dGluZy4KIycKIycgQHJldHVybiBnZ3Bsb3QyIG9iamVjdAojJyBAZXhwb3J0CiMnCnBsb3RfZW1iZWRkaW5nIDwtIGZ1bmN0aW9uKGVtYmVkZGluZ19tYXQsY29sb3VyLHJhbmRvbWl6ZT1ULCBzaXplX3BvaW50PTAuMDUpIHsKICAjIGNyZWF0ZSBhIGRhdGEgZnJhbWUgdGhhdCB3aWxsIGhhdmUgdGhlIGVtYmVkZGluZyBhcyB3ZWxsIGFzIHRoZSBjb2xvcnMKICBlbWJlZGRpbmdfb2JqIDwtIGRhdGEuZnJhbWUoCiAgICBEaW0xPWVtYmVkZGluZ19tYXRbLDFdLAogICAgRGltMj1lbWJlZGRpbmdfbWF0WywyXSwKICAgIFZhcj1jb2xvdXIgKQoKICAjIHJhbmRvbWl6ZSB0aGUgb3JkZXIgb2YgdGhlIG9iamVjdHMKICBpZiggcmFuZG9taXplICkgewogICAgZW1iZWRkaW5nX29iaiA8LSBlbWJlZGRpbmdfb2JqWyBzYW1wbGUuaW50KG5yb3coZW1iZWRkaW5nX29iaikpLCBdCiAgfQogICMgY3JlYXRlIHRoZSBwbG90cwogIGlmKGlzLm51bWVyaWMoY29sb3VyKSkgIyB0aGUgY29sb3IgdmFyaWFibGUgaXMgbnVtZXJpYwogIHsKICAgICNlbWJlZGRpbmdfb2JqJFZhciA8LSBlbWJlZGRpbmdfb2JqJFZhciAtIG1lYW4oZW1iZWRkaW5nX29iaiRWYXIpCiAgICBsaW0gPC0gc3RhdHM6OnF1YW50aWxlKGFicyhlbWJlZGRpbmdfb2JqJFZhciksMC45OSkKICAgIGdncGxvdDI6OmdncGxvdCgKICAgICAgZW1iZWRkaW5nX29iaiwgZ2dwbG90Mjo6YWVzX3N0cmluZyggeD0iRGltMSIsIHk9IkRpbTIiLCBjb2xvdXI9IlZhciIpKSsKICAgICAgZ2dwbG90Mjo6Z2VvbV9wb2ludChzaXplPXNpemVfcG9pbnQpKwogICAgICBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKCkrCiAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50biggbGltaXRzPWMoLWxpbSxsaW0pLCBjb2xvdXJzPWMoImJsdWUiLCJsaWdodCBncmV5IiwicmVkIiksIG9vYj1zY2FsZXM6OnNxdWlzaCApCiAgfSBlbHNlIHsKICAgIGdncGxvdDI6OmdncGxvdCgKICAgICAgZW1iZWRkaW5nX29iaiwgZ2dwbG90Mjo6YWVzX3N0cmluZyggeD0iRGltMSIsIHk9IkRpbTIiLCBjb2xvdXI9IlZhciIpKSsKICAgICAgZ2dwbG90Mjo6Z2VvbV9wb2ludChzaXplPXNpemVfcG9pbnQpKwogICAgICBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKCkrCiAgICAgIGdncGxvdDI6Omd1aWRlcyhjb2xvdXI9Z2dwbG90Mjo6Z3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcz1saXN0KHNpemU9MykpKQoKICB9Cn0KCgpgYGAKCgojIExvYWRpbmcgZGF0YQoKYGBge3J9CgojIFJlYWRpbmcgU0NFIG9iamVjdApzY2U8LSBsb2FkSERGNVN1bW1hcml6ZWRFeHBlcmltZW50KGRpcj1kaXJfZGF0YV9oZGY1KQptZXRhPC0gZGF0YS5mcmFtZShjb2xEYXRhKHNjZSkpCgojIFJlYWRpbmcgR0VESSBtb2RlbCAoIGNvaG9ydDEgcmVzdWx0cykKbW9kZWw8LSByZWFkUkRTKHBhc3RlMChkaXJfZGF0YSwgIkNPVklEMTlfZ2VkaV9tb2RlbF9jb2hvcnQxLnJkcyIpKQoKIyByZW9yZGVyIG1ldGEgYmFzZWQgb24gR0VESSBvcmRlcgptZXRhPC0gbWV0YVttb2RlbCRhdXgkY2VsbElEcyxdCgpgYGAKCgojIFZlY3RvciBmaWVsZHMKCiMjIFNldmVyZSB2cyBjb250cm9sCgpgYGB7ciwgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9N30KCnQoIG1vZGVsJGF1eCRpbnB1dEgpCgojIFByb2plY3QgdGhlIHZlY3RvciBmaWVsZCBvbiB0aGUgU1ZEIHNwYWNlCnZlY3RvckZpZWxkIDwtIHN2ZC52ZWN0b3JGaWVsZC5nZWRpKAogIG1vZGVsLCBzdGFydC5jb25kID0gYygxLDAsMCksIGVuZC5jb25kID0gYygxLDAsMSksIHNjYWxlX2NvbmRfdmVjdG9yPTAuMyApCiMgVGhlIHZlY3RvckZpZWxkIGxpc3QgY29udGFpbnMgdGhlIFNWRCByZXN1bHRzOgojICBUaGUgJ3UnIG9iamVjdCBjb250YWlucyB0aGUgZ2VuZSBsb2FkaW5ncyAoSnhLKQojICBUaGUgJ2QnIG9iamVjdCBpcyB0aGUgc2luZ3VsYXIgdmFsdWVzCiMgIFRoZSAndicgb2JqZWN0IGlzIGEgMk4geCBLIG1hdHJpeCwgd2l0aCB0aGUgZmlyc3QgTiByb3dzIGNvbnRhaW5pbmcgdGhlCiMgICBzdGFydCBjb29yZGluYXRlcywgYW5kIHRoZSBzZWNvbmQgTiByb3dzIGNvbnRhaW5pbmcgdGhlIGVuZCBjb29yZGluYXRlcwoKIyBHZXR0aW5nIG92ZXJhbGwgdmVsb2NpdHkKRGlmZkV4cCA8LSBnZXREaWZmRXhwLmdlZGkoIG1vZGVsLCBjKDAsMCwxKSApIAp2ZWxvY2l0eTwtIGNvbFN1bXMoRGlmZkV4cF4yKQoKYGBgCgpgYGB7cn0KCiMgRXVjbGlkZWFuIGRpc3RhbmNlCnNldC5zZWVkKDQzKQp1bWFwX3ZlY3RvckZpZWxkIDwtIHVtYXAoCiAgdmVjdG9yRmllbGQkdiAlKiUgZGlhZyh2ZWN0b3JGaWVsZCRkKSwgbWluX2Rpc3Q9MC41LAogIG1ldHJpYz0iZXVjbGlkZWFuIikKCmBgYAoKRW1iZWRkaW5nIHBsb3RzCgpgYGB7ciwgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9N30KCiMjIENlbGwgdHlwZSBlbWJlZGRpbmcgaW5kaWNlcwpnZ3A8LSBwbG90X2VtYmVkZGluZyggdW1hcF92ZWN0b3JGaWVsZFt2ZWN0b3JGaWVsZCRlbWJlZGRpbmdfaW5kaWNlcyxdLCBtZXRhJGlkLmNlbGx0eXBlKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0ibm9uZSIpCgpnZ3AKCiMjIFNhdmluZyB0aGUgY29sb3JzCmcgPC0gZ2dwbG90X2J1aWxkKGdncCkKCmRmPC0gZyRkYXRhW1sxXV0KZGY8LSB1bmlxdWUoZGZbLGMoImdyb3VwIiwgImNvbG91ciIpXSkKZGY8LSBkZltvcmRlcihkZiRncm91cCksXQp0ZW1wX3ZlYzwtIGxldmVscyhtZXRhJGlkLmNlbGx0eXBlKQp0ZW1wX3ZlYzwtIHRlbXBfdmVjW3RlbXBfdmVjICVpbiUgdW5pcXVlKG1ldGEkaWQuY2VsbHR5cGUpXQpkZiRjZWxsdHlwZTwtIHRlbXBfdmVjCgp2ZWNfY29sb3JzPC0gZGYkY29sb3VyCm5hbWVzKHZlY19jb2xvcnMpPC0gZGYkY2VsbHR5cGUKCgpnZ3A8LSBwbG90X2VtYmVkZGluZyggdW1hcF92ZWN0b3JGaWVsZFt2ZWN0b3JGaWVsZCRlbWJlZGRpbmdfaW5kaWNlcyxdLCBtZXRhJGlkLmNlbGx0eXBlKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0icmlnaHQiKQoKbGVnZW5kIDwtIGNvd3Bsb3Q6OmdldF9sZWdlbmQoZ2dwKQoKZ3JpZC5uZXdwYWdlKCkKZ3JpZC5kcmF3KGxlZ2VuZCkKCiMjIERvbm9yIGVtYmVkZGluZyBpbmRpY2VzCnBsb3RfZW1iZWRkaW5nKCB1bWFwX3ZlY3RvckZpZWxkW3ZlY3RvckZpZWxkJGVtYmVkZGluZ19pbmRpY2VzLF0sIG1ldGEkZG9ub3IpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSJub25lIikKCmdncDwtIHBsb3RfZW1iZWRkaW5nKCB1bWFwX3ZlY3RvckZpZWxkW3ZlY3RvckZpZWxkJGVtYmVkZGluZ19pbmRpY2VzLF0sIG1ldGEkZG9ub3IpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSJyaWdodCIpCgpsZWdlbmQgPC0gY293cGxvdDo6Z2V0X2xlZ2VuZChnZ3ApCgpncmlkLm5ld3BhZ2UoKQpncmlkLmRyYXcobGVnZW5kKQoKYGBgCgpWZWN0b3IgZmllbGQgcGxvdHMKCmBgYHtyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD03fQoKIyMgQ2VsbCB0eXBlIApwbG90X3ZlY3RvckZpZWxkKCB1bWFwX3ZlY3RvckZpZWxkLCBtZXRhJGlkLmNlbGx0eXBlLCBuYmluPTUwLCBtaW5OdW09MzAgKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0ibm9uZSIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9dmVjX2NvbG9ycykKCmdncDwtIHBsb3RfdmVjdG9yRmllbGQoIHVtYXBfdmVjdG9yRmllbGQsIG1ldGEkaWQuY2VsbHR5cGUsIG5iaW49NTAsIG1pbk51bT0zMCApICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSJyaWdodCIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9dmVjX2NvbG9ycyApCgpsZWdlbmQgPC0gY293cGxvdDo6Z2V0X2xlZ2VuZChnZ3ApCgpncmlkLm5ld3BhZ2UoKQpncmlkLmRyYXcobGVnZW5kKQoKYGBgCgpCb3hwbG90IG9mIHRoZSBtYWduaXR1ZGUgb2YgdGhlIGdlbmUgZXhwcmVzc2lvbiBjaGFuZ2VzCgpgYGB7cn0KCm1ldGEkdmVsb2NpdHlfc2V2ZXJlPC0gdmVsb2NpdHkgCgojIyBsaW1pdCBmb3IgYm94cGxvdApsaW0gPC0gc3RhdHM6OnF1YW50aWxlKGFicyhtZXRhJHZlbG9jaXR5X3NldmVyZSksMC45OTkpCm1ldGEkaWQuY2VsbHR5cGU8LSBmYWN0b3IobWV0YSRpZC5jZWxsdHlwZSwgbGV2ZWxzPXJldihsZXZlbHMobWV0YSRpZC5jZWxsdHlwZSkgKSApCgpnZ3A8LSBnZ3Bsb3QobWV0YSwgYWVzKHZlbG9jaXR5X3NldmVyZSxpZC5jZWxsdHlwZSwgY29sb3IgPSBpZC5jZWxsdHlwZSApICkgKwogICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgeGxpbSgwLCBsaW0pICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9dmVjX2NvbG9ycykgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9Im5vbmUiKQoKZ2dwCgoKYGBgCgoKYGBge3J9CgpzZXNzaW9uSW5mbygpCgpgYGAK